/************************************************************************
                                                                     
   Xceed Ultimate ListBox for Silverlight                                                                                                                                            
   Copyright (C) 2010 Xceed Software Inc.    
                                                                     
   This program is provided to you under the terms of the GNU General Public  
   License version 2 as published by the Free Software Foundation. 
        
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along 
   with this program, if not, write to the Free Software Foundation, Inc., 
   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

   This program can be provided to you by Xceed Software Inc. under a
   proprietary commercial license agreement for use in non-Open Source
   projects. Visit Xceed.com to find the commercial edition of 
   Xceed Ultimate ListBox for Silverlight.                                    
                                                                      
 **********************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Xceed.Silverlight.Data.Stats;
using Xceed.Silverlight.Data.Utils;

namespace Xceed.Silverlight.Data
{
  public class ParentDataSourceProvider : DataSourceProvider, IBufferConfigurable
  {
    #region Constructor

    internal ParentDataSourceProvider( DataSourceProvider dataSourceProvider )
    {
      if( dataSourceProvider == null )
        throw new ArgumentNullException( "dataSourceProvider" );

      m_childDataSourceProvider = dataSourceProvider;
      m_childDataSourceChangedEventListener = new DataSourceChangedEventListener( this.OnChildDataSourceChanged );

      DataSourceChangedEventManager.AddListener( dataSourceProvider, m_childDataSourceChangedEventListener );

      if( !( dataSourceProvider is IBufferConfigurable ) )
      {
        m_bufferConfiguration = ( this.IsBufferingAllowed )
                                  ? new DynamicBufferConfiguration()
                                  : null;
      }
    }

    #endregion

    #region CanCount Property

    public override bool CanCount
    {
      get
      {
        return m_childDataSourceProvider.CanCount;
      }
    }

    #endregion

    #region CanGroupCount Property

    public override bool CanGroupCount
    {
      get
      {
        return m_childDataSourceProvider.CanGroupCount;
      }
    }

    #endregion

    #region CanCalculateStats Property

    public override bool CanCalculateStats
    {
      get
      {
        return m_childDataSourceProvider.CanCalculateStats;
      }
    }

    #endregion

    #region CanFilter Property

    public override bool CanFilter
    {
      get
      {
        return m_childDataSourceProvider.CanFilter;
      }
    }

    #endregion

    #region CanJump Property

    public override bool CanJump
    {
      get
      {
        return m_childDataSourceProvider.CanJump;
      }
    }

    #endregion

    #region CanFilterGroup Property

    public override bool CanFilterGroup
    {
      get
      {
        return m_childDataSourceProvider.CanFilterGroup;
      }
    }

    #endregion

    #region CanJumpToItem Property

    public override bool CanJumpToItem
    {
      get
      {
        return m_childDataSourceProvider.CanJumpToItem;
      }
    }

    #endregion

    #region CanSkip Property

    public override bool CanSkip
    {
      get
      {
        return m_childDataSourceProvider.CanSkip;
      }
    }

    #endregion

    #region BufferConfiguration Property

    public BufferConfiguration BufferConfiguration
    {
      get
      {
        IBufferConfigurable bufferConfigurable = m_childDataSourceProvider as IBufferConfigurable;

        if( bufferConfigurable != null )
        {
          return bufferConfigurable.BufferConfiguration;
        }
        else
        {
          return m_bufferConfiguration;
        }
      }
      set
      {
        IBufferConfigurable bufferConfigurable = m_childDataSourceProvider as IBufferConfigurable;

        if( bufferConfigurable != null )
        {
          bufferConfigurable.BufferConfiguration = value;
        }
        else if( value != m_bufferConfiguration )
        {
          m_bufferConfiguration = value;
        }
      }
    }

    private BufferConfiguration m_bufferConfiguration; //null

    #endregion

    #region ChildDataSourceProvider Protected Property

    protected DataSourceProvider ChildDataSourceProvider
    {
      get
      {
        return m_childDataSourceProvider;
      }
    }

    #endregion

    #region ElementType Protected Internal Property

    protected internal override Type ElementType
    {
      get
      {
        return m_childDataSourceProvider.ElementType;
      }
    }

    #endregion

    #region CanSort Internal Property

    internal override bool CanSort
    {
      get
      {
        return m_childDataSourceProvider.CanSort;
      }
    }

    #endregion

    #region CanFilterPredicate Internal Property

    internal override bool CanFilterPredicate
    {
      get
      {
        return m_childDataSourceProvider.CanFilterPredicate;
      }
    }

    #endregion

    #region CanJumpToDeletedItem Internal Property

    internal override bool CanJumpToDeletedItem
    {
      get
      {
        return m_childDataSourceProvider.CanJumpToDeletedItem;
      }
    }

    #endregion

    #region PrimaryKeyInfo Internal Property

    internal new IEnumerable<SortDescription> PrimaryKeyInfo
    {
      get
      {
        return m_childDataSourceProvider.PrimaryKeyInfo;
      }
    }

    #endregion

    #region IsAsynchronous Internal Property

    internal override bool IsAsynchronous
    {
      get
      {
        return m_childDataSourceProvider.IsAsynchronous;
      }
    }

    #endregion

    #region IsBufferingAllowed Internal Property

    internal override bool IsBufferingAllowed
    {
      get
      {
        return m_childDataSourceProvider.IsBufferingAllowed;
      }
    }

    #endregion

    #region IsCachingAllowed Internal Property

    internal override bool IsCachingAllowed
    {
      get
      {
        return m_childDataSourceProvider.IsCachingAllowed;
      }
    }

    #endregion

    #region IsPrimaryKeyVolatile Internal Property

    internal override bool IsPrimaryKeyVolatile
    {
      get
      {
        return m_childDataSourceProvider.IsPrimaryKeyVolatile;
      }
    }

    #endregion

    protected override IEnumerable<SortDescription> GetPrimaryKeyInfo()
    {
      return m_childDataSourceProvider.PrimaryKeyInfo;
    }

    protected override void Initialize()
    {
      m_childDataSourceProvider.Init();
    }

    protected virtual void OnChildDataSourceChanged( DataSourceChangedEventArgs e )
    {
      this.OnDataSourceChanged( e );
    }

    protected override void OnInvalidateData()
    {
    }

    protected override void OnInvalidateDataObjects( IEnumerable<ItemChangedDescription> itemsChanged )
    {
    }

    protected override void OnDataObjectsAdded( IEnumerable<object> itemsAdded )
    {
      m_childDataSourceProvider.NotifyItemsAdded( itemsAdded );
    }

    protected override void OnDataObjectsRemoved( IEnumerable<object> itemsRemoved )
    {
      m_childDataSourceProvider.NotifyItemsRemoved( itemsRemoved );
    }

    internal override IAsyncResult BeginExecuteCountQueryCore( 
      CountQueryParameters queryParameters, 
      AsyncCallback callback, 
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteCountQueryInternal( queryParameters, callback, state );
    }

    internal override CountQueryResult EndExecuteCountQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteCountQueryInternal( asyncResult );
    }

    internal override IAsyncResult BeginExecuteDataQueryCore( 
      DataQueryParameters queryParameters, 
      AsyncCallback callback, 
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteDataQueryInternal( queryParameters, callback, state );
    }

    internal override DataQueryResult EndExecuteDataQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteDataQueryInternal( asyncResult );
    }

    internal override IAsyncResult BeginExecuteGroupCountQueryCore( 
      GroupCountQueryParameters queryParameters, 
      AsyncCallback callback, 
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteGroupCountQueryInternal( queryParameters, callback, state );
    }

    internal override GroupCountQueryResult EndExecuteGroupCountQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteGroupCountQueryInternal( asyncResult );
    }

    internal override IAsyncResult BeginExecuteStatQueryCore(
      StatQueryParameters queryParameters,
      AsyncCallback callback,
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteStatQueryInternal( queryParameters, callback, state );
    }

    internal override StatQueryResult EndExecuteStatQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteStatQueryInternal( asyncResult );
    }

    internal override IEnumerable<FilterOperator> SupportedFilterOperators( Type dataType )
    {
      return m_childDataSourceProvider.SupportedFilterOperators( dataType );
    }

    internal override IEnumerable<Type> SupportedStatFunctions( Type dataType )
    {
      return m_childDataSourceProvider.SupportedStatFunctions( dataType );
    }

    internal override bool IsStatFunctionSupportedNatively( StatFunction statFunction )
    {
      return m_childDataSourceProvider.IsStatFunctionSupportedNatively( statFunction );
    }

    internal override bool IsSortOrderSupported( IEnumerable<SortDescription> sortOrder )
    {
      return m_childDataSourceProvider.IsSortOrderSupported( sortOrder );
    }

    internal override bool FindElementMemberType( string memberName, out Type type )
    {
      return m_childDataSourceProvider.FindElementMemberType( memberName, out type );
    }

    internal override bool CanJumpTo( IEnumerable<SortDescription> properties )
    {
      if( !this.CanJump )
        return false;

      return m_childDataSourceProvider.CanJumpTo( properties );
    }

    internal override int GetPageSize()
    {
      int pageSize = base.GetPageSize();
      int childPageSize = m_childDataSourceProvider.GetPageSize();

      if( pageSize > 0 && childPageSize > 0 )
        return Math.Min( pageSize, childPageSize );

      return ( pageSize <= 0 ) ? childPageSize : pageSize;
    }

    internal sealed override void CheckIfStatFunctionIsInCalculation( StatFunction statFunction )
    {
      // The child DataSourceProvider will do the check.
    }

    internal sealed override void SetStatFunctionCalculationState(
      StatFunction statFunction,
      bool inCalculation )
    {
      // The child DataSourceProvider will do the job.
    }

    internal override void InvalidateData()
    {
      m_childDataSourceProvider.InvalidateData();
    }

    internal override void InvalidateDataItem( IEnumerable<ItemChangedDescription> itemsChanged )
    {
      m_childDataSourceProvider.InvalidateDataItem( itemsChanged );
    }

    internal override bool TryWrapDataObject( object item, out RawDataItem dataItem )
    {
      return m_childDataSourceProvider.TryWrapDataObject( item, out dataItem );
    }

    internal override bool TryUnwrapDataObject( RawDataItem dataItem, out object item )
    {
      return m_childDataSourceProvider.TryUnwrapDataObject( dataItem, out item );
    }

    internal override bool TryUnwrapLayer( RawDataItem dataItem, out object item )
    {
      return m_childDataSourceProvider.TryUnwrapLayer( dataItem, out item );
    }

    #region Private Fields

    private DataSourceProvider m_childDataSourceProvider;
    private DataSourceChangedEventListener m_childDataSourceChangedEventListener;

    #endregion

    #region Private DataSourceChangedEventListener Nested Type

    private class DataSourceChangedEventListener : ISLWeakEventListener
    {
      internal DataSourceChangedEventListener( Action<DataSourceChangedEventArgs> dataSourceChangedAction )
      {
        m_dataSourceChangedAction = dataSourceChangedAction;
      }

      bool ISLWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e )
      {
        if( managerType == typeof( DataSourceChangedEventManager ) )
        {
          DataSourceChangedEventArgs dataSourceChangedEventArgs = e as DataSourceChangedEventArgs;
          if( dataSourceChangedEventArgs != null )
          {
            m_dataSourceChangedAction.Invoke( dataSourceChangedEventArgs );
            return true;
          }
        }

        return false;
      }

      private Action<DataSourceChangedEventArgs> m_dataSourceChangedAction;
    }

    #endregion
  }
}
